{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/advance/into-types/intro.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 类型转换\n",
    "\n",
    "- https://course.rs/advance/into-types/converse.html\n",
    "- https://practice-zh.course.rs/type-conversions/as.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/type-conversions/as.md\n",
    "- https://practice-zh.course.rs/type-conversions/from-into.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/type-conversions/from-into.md\n",
    "- https://practice-zh.course.rs/type-conversions/others.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/type-conversions/others.md\n",
    "\n",
    "**TL;DR（Rust 类型转换要点）**\n",
    "\n",
    "- Rust 类型系统严格，比较或运算前需显式转换：使用 `as` 时务必确保目标类型能容纳原值，否则会发生截断。\n",
    "- 想安全捕获转换失败，用 `TryInto/TryFrom`；它们返回 `Result`，可处理溢出等错误。\n",
    "- 指针/地址转换与操作属于 `unsafe` 范畴，需谨慎：先拿裸指针再转整数或反向转换时要保证对齐与有效性。\n",
    "- 强制类型转换（coercions）在方法调用、引用、切片等场景自动发生；点操作符会尝试值调用、引用调用、`Deref`、数组到切片等多步匹配。\n",
    "- 派生或实现 `Clone` 等特征时要注意泛型约束：若内部字段未实现所需特征，编译器只能复制引用。\n",
    "- `mem::transmute` / `transmute_copy` 是最后的“黑魔法”：仅在类型尺寸、布局完全满足且别无他法时才用，并始终在 `unsafe` 中处理。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## as转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m      \u001b[38;5;100m┬\u001b[0m   \u001b[38;5;54m┬\u001b[0m\u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m      \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m expected because this is `i32`",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m│\u001b[0m\u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `i32`, found `u16`",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: you can convert a `u16` to an `i32`: `.into()`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "  let a: i32 = 10;\n",
    "  let b: u16 = 100;\n",
    "\n",
    "  if a < b { // a 和 b 拥有不同的类型，Rust 不允许两种不同的类型进行比较。\n",
    "    println!(\"Ten is less than one hundred.\");\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "{\n",
    "  let a: i32 = 10;\n",
    "  let b: u16 = 100;\n",
    "\n",
    "  if a < (b as i32) { // 因为每个类型能表达的数据范围不同，如果把范围较大的类型转换成较小的类型，会造成错误\n",
    "    println!(\"Ten is less than one hundred.\");\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "127\n"
     ]
    }
   ],
   "source": [
    "let a = i8::MAX;\n",
    "println!(\"{}\",a);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3,100,97\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "   let a = 3.1 as i8;\n",
    "   let b = 100_i8 as i32;\n",
    "   let c = 'a' as u8; // 将字符'a'转换为整数，97\n",
    "\n",
    "   println!(\"{},{},{}\",a,b,c)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 内存地址转换为指针"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "let mut values: [i32; 2] = [1, 2];\n",
    "let p1: *mut i32 = values.as_mut_ptr();\n",
    "let first_address = p1 as usize; // 将p1内存地址转换为一个整数\n",
    "let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>()，i32类型占用4个字节，因此将内存地址 + 4\n",
    "let p2 = second_address as *mut i32; // 访问该地址指向的下一个整数p2\n",
    "unsafe {\n",
    "    *p2 += 1;\n",
    "}\n",
    "assert_eq!(values[1], 3);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 强制类型转换的边角知识\n",
    "\n",
    "转换不具有传递性 就算 `e as U1 as U2` 是合法的，也不能说明 `e as U2` 是合法的（`e` 不能直接转换成 `U2`）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TryInto 转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:135:30:\n",
      "called `Result::unwrap()` on an `Err` value: TryFromIntError(())\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::result::unwrap_failed\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/result.rs:1765:5\n",
      "   3: __rust_try.llvm.9606483390382140662\n",
      "   4: std::panic::catch_unwind\n",
      "   5: run_user_code_5\n",
      "   6: evcxr::runtime::Runtime::run_loop\n",
      "   7: evcxr::runtime::runtime_hook\n",
      "   8: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "use std::convert::TryInto;\n",
    "\n",
    "{\n",
    "   let a: u8 = 10;\n",
    "   let b: u16 = 1500;\n",
    "\n",
    "   let b_: u8 = b.try_into().unwrap();\n",
    "\n",
    "   if a < b_ {\n",
    "     println!(\"Ten is less than one hundred.\");\n",
    "   }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`try_into` 会尝试进行一次转换，并返回一个 `Result`，此时就可以对其进行相应的错误处理。由于我们的例子只是为了快速测试，因此使用了 `unwrap` 方法，该方法在发现错误时，会直接调用 `panic` 导致程序的崩溃退出，在实际项目中，请不要这么使用，具体见[panic](https://course.rs/basic/result-error/panic.html#调用-panic)部分。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"out of range integral type conversion attempted\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let b: i16 = 1500;\n",
    "\n",
    "    let b_: u8 = match b.try_into() { // 程序捕获了错误\n",
    "        Ok(b1) => b1,\n",
    "        Err(e) => {\n",
    "            println!(\"{:?}\", e.to_string());\n",
    "            0\n",
    "        }\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通用类型转换\n",
    "\n",
    "在一个笨办法，将一个结构体转换为另外一个结构体"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Foo {\n",
    "    x: u32,\n",
    "    y: u16,\n",
    "}\n",
    "\n",
    "struct Bar {\n",
    "    a: u32,\n",
    "    b: u16,\n",
    "}\n",
    "\n",
    "fn reinterpret(foo: Foo) -> Bar {\n",
    "    let Foo { x, y } = foo;\n",
    "    Bar { a: x, b: y }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 强制类型转换\n",
    "\n",
    "- `as` / `TryInto` 仅适合数值类型；结构体间转换需手写或实现专门特征。\n",
    "- Rust 存在自动“强制转换”，但只在特定场景：**方法调用（.）** 会尝试值调用 → 自动引用 → 自动解引用 → 固定数组到切片等链式步骤；特征约束本身不会被强制转换。\n",
    "- 引用类型天然实现 `Clone`，缺省泛型若未实现 `Clone`，方法调用最终会退化为复制引用而非值。\n",
    "- `derive(Clone)` 会自动生成 `where T: Clone`，若泛型未满足，就只能对引用做自动 Clone；必要时需手写实现。\n",
    "- `mem::transmute` / `transmute_copy` 是“核武器”：仅当内存布局、大小、生命周期都 100% 对齐时才可用，否则即未定义行为；大多数情况下应避免。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个类型 `T` 可以强制转换为 `U`，不代表 `impl T` 可以强制转换为 `impl U`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Trait {}\n",
    "\n",
    "fn foo<X: Trait>(t: X) {}\n",
    "\n",
    "impl<'a> Trait for &'a i32 {}\n",
    "\n",
    "fn main() {\n",
    "    let t: &mut i32 = &mut 0; // `Trait` is implemented for `&i32`, but not for `&mut i32`\n",
    "    foo(t);\n",
    "}"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "error[E0277]: the trait bound `&mut i32: Trait` is not satisfied\n",
    " --> <source>:9:9\n",
    "  |\n",
    "9 |     foo(t);\n",
    "  |     --- ^ the trait `Trait` is not implemented for `&mut i32`\n",
    "  |     |\n",
    "  |     required by a bound introduced by this call\n",
    "  |\n",
    "  = help: the trait `Trait` is implemented for `&i32`\n",
    "  = note: `Trait` is implemented for `&i32`, but not for `&mut i32`\n",
    "note: required by a bound in `foo`\n",
    " --> <source>:3:11\n",
    "  |\n",
    "3 | fn foo<X: Trait>(t: X) {}\n",
    "  |           ^^^^^ required by this bound in `foo`\n",
    "\n",
    "warning: unused variable: `t`\n",
    " --> <source>:3:18\n",
    "  |\n",
    "3 | fn foo<X: Trait>(t: X) {}\n",
    "  |                  ^ help: if this is intentional, prefix it with an underscore: `_t`\n",
    "  |\n",
    "  = note: `#[warn(unused_variables)]` on by default\n",
    "\n",
    "error: aborting due to 1 previous error; 1 warning emitted\n",
    "\n",
    "For more information about this error, try `rustc --explain E0277`.\n",
    "Compiler returned: 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### * 点操作符\n",
    "\n",
    "TL;DR\n",
    "- Rust 的点操作符在方法调用时会经历一系列尝试：先以值类型调用，再自动引用，最后自动解引用和定长到不定长的转换，直到找到合适的方法实现。\n",
    "- 对于 `value.foo()`，编译器会在 `T::foo(value)`、`<&T>::foo(value)`、`<&mut T>::foo(value)`、`U::foo(*)`（若 `T: Deref<Target=U>`）以及“定长→不定长”转换后逐一尝试。\n",
    "- 数组索引 `array[0]` 实际是 `Index` 特征的语法糖，会触发同样的查找过程，最终定位到实现 `Index` 的切片类型 `[T]`。\n",
    "- 自动引用/解引用会影响方法返回类型推断：即便 `T` 没实现 `Clone`，`&T` 还是能调用 `clone()` 返回 `&T`。\n",
    "- 泛型场景下，自动引用会导致方法返回值与直觉不同，如 `Container<T>` 未手动实现 `Clone` 时，`&Container<T>` 调用 `clone()` 仅复制引用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**触发的“魔法”：方法查找流程**\n",
    "\n",
    "假设有一个方法 `foo`，它有一个接收器(接收器就是 `self`、`&self`、`&mut self` 参数)。\n",
    "\n",
    "当你写下 `value.foo()` 时，编译器必须决定使用哪一种 `Self` 类型来调用 `foo`。假设 `value` 的静态类型为 `T`，编译器会按以下顺序寻找可行的调用方式：\n",
    "\n",
    "1. **值方法调用**：尝试 `T::foo(value)`。\n",
    "   - 如果 `T` 上存在符合签名的 `foo` 方法（包括实现于 `impl T` 或 `impl Trait for T`），直接调用。\n",
    "2. **引用方法调用**：若上一条失败，分别尝试 `(&T)::foo(value)` 和 `(&mut T)::foo(value)`。\n",
    "   - 需注意 `value` 暂时被借用，因此调用实际是 `foo(&value)` 或 `foo(&mut value)` 的等价形式。\n",
    "3. **解引用方法调用**：若仍失败，检查 `T` 是否实现 `Deref` / `DerefMut`。\n",
    "   - 若 `T: Deref<Target = U>`，编译器把问题转换为 `U::foo(*value)`，递归执行上述流程。\n",
    "4. **定长到不定长转换**：当 `T` 是定长数组 `[T; N]` 等类型时，编译器会尝试把它视作切片 `[T]`、`str` 等不定长类型再继续查找。\n",
    "5. **放弃**：当所有尝试都失败，编译器报错。\n",
    "\n",
    "这一序列说明了点操作符“自动引用”“自动解引用”“强制类型转换”的由来——它们都是编译器为了找到合法方法实现而进行的逐步尝试。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**数组索引的多层拆解**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let array: Rc<Box<[T; 3]>> = ...;\n",
    "let first_entry = array[0];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`array[0]` 是 `Index` 特征的语法糖，等价于 `array.index(0)`。查找路径如下：\n",
    "\n",
    "1. 是否存在 `impl Index<usize> for Rc<Box<[T; 3]>>`？没有。\n",
    "2. 尝试引用类型 `&Rc<Box<[T; 3]>>`、`&mut Rc<Box<[T; 3]>>`，仍没有。\n",
    "3. 解引用 `Rc` → `Box<[T; 3]>`，重复步骤 1、2，仍无。\n",
    "4. 再次解引用 `Box<[T; 3]>` → `[T; 3]`。\n",
    "5. `[T; 3]` 和其引用也没实现 `Index`。\n",
    "6. “定长→不定长”转换：`[T; 3]` 强制为 `[T]`（切片），它实现了 `Index`，查找成功。\n",
    "\n",
    "这解释了为何尽管静态类型是 `Rc<Box<[T; 3]>>`，仍然能使用数组索引语法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**自动引用对返回类型的影响**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 编译器匹配到 `fn clone(&T) -> T`，直接值方法调用，返回所有权 `T`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 有 `Clone` 约束\n",
    "\n",
    "fn do_stuff<T: Clone>(value: &T) {\n",
    "    let cloned = value.clone(); // cloned: T\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `T::clone` 不可用，于是尝试引用方法调用。\n",
    "- `&T` 实现了 `Clone`（复制指针），签名 `fn clone(&&T) -> &T`。\n",
    "- 结果复制的是引用，`cloned` 类型为 `&T`，而非 `T`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 无 `Clone` 约束\n",
    "\n",
    "// 这个例子强调了：自动引用使无 `Clone` 约束的情况下仍能调用 `clone`，但返回的是借用。\n",
    "fn do_stuff<T>(value: &T) {\n",
    "    let cloned = value.clone(); // cloned: &T\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**泛型容器的案例分析**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Clone)]\n",
    "struct Container<T>(Arc<T>);\n",
    "\n",
    "fn clone_containers<T>(foo: &Container<i32>, bar: &Container<T>) {\n",
    "    let foo_cloned = foo.clone();\n",
    "    let bar_cloned = bar.clone();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `Container<i32>`：因为 `i32: Clone`，推导的 `impl Clone for Container<i32>` 存在。`foo.clone()` 走值方法调用，返回类型 `Container<i32>`。\n",
    "- `Container<T>`：派生 `Clone` 要求 `T: Clone`。在泛型 `T` 没约束时，`Container<T>` **没有**实现 `Clone`。\n",
    "  - 编译器改尝试引用方法调用，`&Container<T>` 是可 `Clone` 的引用 -> `bar_cloned: &Container<T>`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "手动为 `Container<T>` 写 `Clone` 实现并去掉 `T: Clone` 约束即可让 `bar_cloned` 返回拥有所有权的 `Container<T>`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "impl<T> Clone for Container<T> {\n",
    "    fn clone(&self) -> Self {\n",
    "        Self(Arc::clone(&self.0))\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**点操作符背后的设计哲学**\n",
    "\n",
    "- **渐进式查找**：通过自动引用、自动解引用、强制转换等“魔法”，让调用者用最自然的语法即可访问深层数据。\n",
    "- **安全优先**：每一步转化都遵循所有权和借用规则，保证类型安全。\n",
    "- **对泛型敏感**：在泛型上下文中要特别注意约束，编译器的自动行为常会导致返回类型与直觉不一致。\n",
    "- **工作量在编译器**：多层查找隐藏了复杂性，让大多数场景都“看起来很简单”，但了解底层过程有助于分析报错和实现自定义类型。\n",
    "\n",
    "当你看到“这个方法怎么能用？明明类型不匹配啊”的时候，十有八九是点操作符在背后做了大量尝试。理解这些步骤，不仅能读懂编译器的错误提示，也能写出更直观、健壮的 Rust 代码。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 变形记(Transmutes)\n",
    "\n",
    "TL;DR\n",
    "\n",
    "- `std::mem::transmute` 会在**没有任何类型检查**的情况下，把一块原始内存重新解释成另一种类型，只要两者占用的字节数一致。几乎所有类型系统的安全保障都会被绕过，一旦误用就是未定义行为（UB）。\n",
    "- 典型危险：乱造值、滥用引用（`&` ↔ `&mut`）、随意改生命周期、错误的内存布局假设、ZST/对齐/`Drop` 冲突等。\n",
    "- `transmute_copy` 比 `transmute` 更狠：连“大小必须相等”的检查都没有，极易导致读取未初始化内存、重复 Drop 等灾难。\n",
    "- 唯一合理的用法是**非常明确地**掌握内存布局，并且确认没有更安全的替代手段（`ptr::cast`、`MaybeUninit`、`from_ne_bytes`、Ffi 类型、手写 `repr(C)` 等）。\n",
    "- 在实践中，应把 `transmute` 当成最后手段，封装在 `unsafe` 模块里并附带详尽的安全性证明和注释。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#####  什么是 `std::mem::transmute`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub unsafe fn transmute<T, U>(t: T) -> U"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **编译期检查**只有一项：`size_of::<T>() == size_of::<U>()`。\n",
    "- 实际行为：直接把 `t` 的比特模式当成 `U` 来解释，完全跳过 Rust 的类型系统。\n",
    "- 结果：你得到一个“看似合法”的 `U`，但该值是否有效、对齐是否正确、Drop 是否安全，全都成谜。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 未定义行为的雷区\n",
    "\n",
    "**核心结论**：除非你能写下详尽、可信的安全性证明，否则 `transmute` 随时会爆炸。\n",
    "\n",
    "| 序号 | 问题类别          | 示例/场景                                       | 危险原因或未定义行为说明                                     | 备注/替代方案提示                                            |\n",
    "| :--: | ----------------- | ----------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "|  1   | 伪造值            | `mem::transmute::<u8, bool>(3)`                 | `bool` 仅允许 0/1；强行解释任意比特会得到不合法值 → UB       | 使用受限转换（如 `bool::from`、`TryFrom`）或手写检查         |\n",
    "|  2   | 借用规则破坏      | `&T` → `&mut T`                                 | 可变引用要求独占别名；从共享借用“升级”为可变借用必定违反别名规则 | 没有安全替代；应通过原生可变引用或内部可变性（`Cell`/`RefCell`） |\n",
    "|  3   | 生命周期造假      | 延长到 `'static`，或随意缩短静态生命周期        | 打破编译器推断的有效期，造成悬垂引用或过早释放 → UB          | 使用安全生命周期抽象（`Arc`/`Box::leak`/`Cow` 等），或在 `unsafe` 封装中严格证明 |\n",
    "|  4   | 内存布局不匹配    | `repr(Rust)` 结构体、`Vec<i32>` ↔ `Vec<u32>`    | 默认布局无顺序/填充保证，字段位置可能变化；跨泛型版本布局可能不同 → UB | 仅对 `#[repr(C)]`、`#[repr(transparent)]`、`#[repr(u8)]` 等显式布局类型使用 |\n",
    "|  5   | 对齐与 ZST        | ZST 转换、不同对齐要求的类型                    | 目标类型对齐可能更严格，读取/写入时违反对齐；ZST 常被优化，`transmute` 后行为不可预期 | 使用 `ptr::cast` 等明确处理对齐；对 ZST 采用其它语义表达（`PhantomData`、零成本泛型） |\n",
    "|  6   | Drop 语义错乱     | `T` 被忘记 Drop，或 `U` 在无效比特下执行 Drop   | `transmute` 本质为移动：原 `T` 被遗弃；若 `U` Drop 使用无效值可能双重释放/未初始化访问 | 结合 `ManuallyDrop`、`MaybeUninit` 管控析构；确保目标类型处于有效状态 |\n",
    "|  7   | 泛型/枚举内部不稳 | 标准库内部字段（例如 `Vec`、枚举 discriminant） | 标准库随版本修改内部实现；依赖私有布局会在升级时静默失效 → UB | 只依赖文档承诺的 `repr` 和公开 API；关注 release note 与 `mem::transmute` 相关的变动 |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### `transmute_copy`：深渊更深"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub unsafe fn transmute_copy<T, U>(src: &T) -> U"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 从 `src` 读出 `mem::size_of::<U>()` 个字节，直接视作 `U`。\n",
    "- 不检查大小，不转移所有权（`T` 仍会被 Drop）。\n",
    "- UB 高发场景：\n",
    "  - `size_of::<U>() > size_of::<T>()`：读取未初始化内存。\n",
    "  - `U` 有 `Drop` → 未初始化的 Drop。\n",
    "  - `T` / `U` 含引用 → 纯凭运气。\n",
    "  - `U` 需要对齐 → 可能 misalign。\n",
    "- 总结：除非你正在写编译器内核或 runtime，几乎没有使用理由。官方文档也几乎只用于专业级底层黑魔法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 有限的合法用途\n",
    "\n",
    "即便如此，也要优先寻找 **安全或更受限的 `unsafe` 替代方案**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**裸指针 ↔ 函数指针**\n",
    "- 替代：`pointer.cast::<fn() -> i32>()`（稳定版 `UnsafeCell::raw_get` 之后会更好）。\n",
    "- 必须确认裸指针确实指向正确的函数符号。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn foo() -> i32 { 0 }\n",
    "\n",
    "let pointer = foo as *const ();\n",
    "let function = unsafe {\n",
    "    std::mem::transmute::<*const (), fn() -> i32>(pointer)\n",
    "};\n",
    "assert_eq!(function(), 0);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**生命周期“调整”**\n",
    "- 常见用途是把 `&'a T` 塞进 `'static` 容器（全局 cache、FFI 持久化等）。\n",
    "- 风险：若 `r` 原本生命周期很短，就会产生悬垂引用。\n",
    "- 替代：`std::mem::transmute::<_, _>` 可以被 `std::mem::ManuallyDrop`、`Pin`、`PhantomData` 等手段替代；通常需要配合 `unsafe` 封装 + 严格使用约定。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct R<'a>(&'a i32);\n",
    "\n",
    "unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {\n",
    "    std::mem::transmute::<R<'b>, R<'static>>(r)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 更安全的替代方案\n",
    "\n",
    "- **枚举/整数互转**：`num::FromPrimitive`，`TryFrom`，`from_ne_bytes`。\n",
    "- **指针转换**：`ptr::cast`, `ptr::cast_mut`, `ptr::from_raw_parts`.\n",
    "- **布局控制**：使用 `#[repr(C)]`, `#[repr(transparent)]`, `#[repr(align(N))]`.\n",
    "- **未初始化内存**：`MaybeUninit`, `ptr::read`, `ptr::write`.\n",
    "- **生命周期问题**：`Arc`, `Rc`, `Box::leak`, `Cow`, `PhantomData`.\n",
    "- **类型擦除**：`Any`, trait objects, `dyn Trait`.\n",
    "\n",
    "> 只要存在以上替代方案之一，就说明你不应该使用 `transmute`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 使用 `transmute` 的最低限度守则\n",
    "\n",
    "1. **封装在私有 `unsafe` 工具函数里**，附带证明。\n",
    "2. **注释详细说明不变量**：布局、对齐、生命周期、Drop 行为、泛型约束。\n",
    "3. **测试 + Miri 检查**：`cargo miri test` 可以捕捉部分 UB，但不是万能。\n",
    "4. **关注版本升级**：依赖标准库内部布局时要关注 release note。\n",
    "5. **审计**：任何 `transmute` 代码都需要额外代码审查。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# newtype 和 类型别名\n",
    "\n",
    "- https://course.rs/advance/into-types/custom-type.html\n",
    "\n",
    "TL;DR\n",
    "\n",
    "- **Newtype** (`struct Wrapper(T);`) 创建全新类型：绕开孤儿规则、提升语义表达、隔离内部实现；与原类型完全不同。\n",
    "- **类型别名** (`type Alias = T;`) 只是同一类型的新名字：改善可读性、复用长类型签名，但无法改变语义，也不能突破孤儿规则。\n",
    "- **永不返回类型 `!`** 表示“此代码路径不会产生值”，让 `match` 等表达式在无法产生统一返回值时依旧编译通过（如 `panic!`、`loop {}`, `return`）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## newtype\n",
    "\n",
    "- **newtype = 元组结构体包装**：`struct Meters(u32);` 让旧类型穿上新外衣，获得独立身份。\n",
    "- **突破孤儿规则**：用新包装的自有类型为标准库类型实现标准库 trait（如 `Display`）。\n",
    "- **语义更鲜明 + 类型隔离**：`Meters` 与 `MilliMeters` 编译器视为完全不同，避免单位混淆。\n",
    "- **可见性控制**：屏蔽底层方法（尽管可通过 `.0` 访问，仍具一定封装意义）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 为外部类型实现外部特征\n",
    "\n",
    "在之前的章节中，我们有讲过，如果在外部类型上实现外部特征必须使用 `newtype` 的方式，否则你就得遵循孤儿规则：要为类型 `A` 实现特征 `T`，那么 `A` 或者 `T` 必须至少有一个在当前的作用范围内。\n",
    "\n",
    "例如，如果想使用 `println!(\"{}\", v)` 的方式去格式化输出一个动态数组 `Vec`，以期给用户提供更加清晰可读的内容，那么就需要为 `Vec` 实现 `Display` 特征，但是这里有一个问题： `Vec` 类型定义在标准库中，`Display` 亦然，这时就可以祭出大杀器 `newtype` 来解决：\n",
    "\n",
    "使用元组结构体语法 `struct Wrapper(Vec<String>)` 创建了一个 `newtype` Wrapper，然后为它实现 `Display` 特征，最终实现了对 `Vec` 动态数组的格式化输出。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w = [hello, world]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::fmt;\n",
    "\n",
    "struct Wrapper(Vec<String>);\n",
    "\n",
    "impl fmt::Display for Wrapper {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"[{}]\", self.0.join(\", \"))\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let w = Wrapper(vec![String::from(\"hello\"), String::from(\"world\")]);\n",
    "    println!(\"w = {}\", w);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 更好的可读性及类型异化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "目标地点距离你30米\n"
     ]
    }
   ],
   "source": [
    "use std::ops::Add;\n",
    "use std::fmt;\n",
    "\n",
    "struct Meters(u32);\n",
    "impl fmt::Display for Meters {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"目标地点距离你{}米\", self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Add for Meters {\n",
    "    type Output = Self;\n",
    "\n",
    "    fn add(self, other: Meters) -> Self {\n",
    "        Self(self.0 + other.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let d = calculate_distance(Meters(10), Meters(20));\n",
    "    println!(\"{}\", d);\n",
    "}\n",
    "\n",
    "fn calculate_distance(d1: Meters, d2: Meters) -> Meters {\n",
    "    d1 + d2\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **语义清晰**：`Latitude`、`Longitude` 一眼就能看出含义；`Coordinate::new` 的签名也明确约束了参数顺序。\n",
    "- **类型异化**：虽然都包裹 `f64`，但互不兼容，编译器防止我们把经纬度颠倒。\n",
    "- **扩展性**：可在 wrapper 内提供自定义方法（如校验范围、格式化输出）而不污染所有 `f64`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;\n",
    "\n",
    "/// 包装纬度数值，使用 newtype 让纬度拥有独立的类型身份\n",
    "#[derive(Debug, Copy, Clone, PartialEq)]\n",
    "struct Latitude(f64);\n",
    "\n",
    "/// 包装经度数值，同样让经度与普通 `f64` 区分开\n",
    "#[derive(Debug, Copy, Clone, PartialEq)]\n",
    "struct Longitude(f64);\n",
    "\n",
    "impl fmt::Display for Latitude {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // 自定义纬度的输出格式：保留四位小数并附上方向标记\n",
    "        write!(f, \"{:.4}°N\", self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "impl fmt::Display for Longitude {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // 自定义经度的输出格式\n",
    "        write!(f, \"{:.4}°E\", self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 使用纬度与经度 newtype 组合出一个地理坐标类型\n",
    "#[derive(Debug)]\n",
    "struct Coordinate {\n",
    "    lat: Latitude,\n",
    "    lon: Longitude,\n",
    "}\n",
    "\n",
    "impl Coordinate {\n",
    "    /// 构造函数，强制要求调用者按照正确的纬度→经度顺序传参\n",
    "    fn new(lat: Latitude, lon: Longitude) -> Self {\n",
    "        Self { lat, lon }\n",
    "    }\n",
    "\n",
    "    /// 将坐标格式化为 `(纬度, 经度)` 形式，自动调用各自的 Display 实现\n",
    "    fn format(&self) -> String {\n",
    "        format!(\"({}, {})\", self.lat, self.lon)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 清晰表达：39.9042 这个数值代表纬度\n",
    "    let lat = Latitude(39.9042);\n",
    "    // 清晰表达：116.4074 这个数值代表经度\n",
    "    let lon = Longitude(116.4074);\n",
    "\n",
    "    // 无法传错顺序：编译器会在这里检查类型\n",
    "    let beijing = Coordinate::new(lat, lon);\n",
    "    println!(\"北京天安门：{}\", beijing.format());\n",
    "\n",
    "    // 解除注释即可看到编译错误：\n",
    "    //\n",
    "    // let wrong = Coordinate::new(lon, lat);\n",
    "    //              ^^^^^^^^ expected `Latitude`, found `Longitude`\n",
    "    //\n",
    "    // 这就是 newtype 带来的“类型异化”：经度和纬度虽然都包裹 f64，却被当作完全不同的类型，\n",
    "    // 彻底杜绝了把参数顺序写反的低级错误。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 隐藏内部类型的细节\n",
    "\n",
    "众所周知，Rust 的类型有很多自定义的方法，假如我们把某个类型传给了用户，但是又不想用户调用这些方法，就可以使用 `newtype`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Meters(u32);\n",
    "\n",
    "fn main() {\n",
    "    let i: u32 = 2;\n",
    "    assert_eq!(i.pow(2), 4);\n",
    "\n",
    "    let n = Meters(i);\n",
    "    // 下面的代码将报错，因为`Meters`类型上没有`pow`方法\n",
    "    // assert_eq!(n.pow(2), 4);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "不过需要偷偷告诉你的是，这种方式实际上是掩耳盗铃，因为用户依然可以通过 `n.0.pow(2)` 的方式来调用内部类型的方法 :)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类型别名(Type Alias)\n",
    "\n",
    "- `type Alias = T;` 只是给现有类型换个名字，语义不变，编译器照样把它当作原类型使用。\n",
    "- 类型别名无法绕过孤儿规则，也不能创造“全新类型”；只负责提升可读性、减少冗长标注。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type Meters = u32 // 类型别名并不是一个独立的全新的类型，而是某一个类型的别名，因此编译器依然会把 Meters 当 u32 来使用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x + y = 10\n"
     ]
    }
   ],
   "source": [
    "type Meters = u32;\n",
    "\n",
    "let x: u32 = 5;\n",
    "let y: Meters = 5;\n",
    "\n",
    "println!(\"x + y = {}\", x + y);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 常用于压缩复杂类型签名（如 `Box<dyn Fn() + Send + 'static>` → `Thunk`）和标准库的 `std::io::Result<T>` 等别名。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!(\"hi\"));\n",
    "\n",
    "fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type Thunk = Box<dyn Fn() + Send + 'static>; // 提高模板代码的可读性\n",
    "\n",
    "let f: Thunk = Box::new(|| println!(\"hi\"));\n",
    "\n",
    "fn takes_long_type(f: Thunk) {\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "fn returns_long_type() -> Thunk {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type Result<T> = std::result::Result<T, std::io::Error>;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 因为与原类型完全等价，别名仍可调用原类型全部方法，包含 `?` 等语法糖。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## !永不返回类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在[函数](https://course.rs/basic/base-type/function.html#永不返回的函数)那章，曾经介绍过 `!` 类型：`!` 用来说明一个函数永不返回任何值，当时可能体会不深，没事，在学习了更多手法后，保证你有全新的体验："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`match` arms have incompatible types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m `match` arms have incompatible types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_18:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;68m╭\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m▶\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68mc\u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m{\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;68m│\u001b[0m   \u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m0\u001b[0m\u001b[38;5;68m.\u001b[0m\u001b[38;5;68m.\u001b[0m\u001b[38;5;68m=\u001b[0m\u001b[38;5;68m3\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m=\u001b[0m\u001b[38;5;68m>\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;68m,\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m│\u001b[0m                   \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m│\u001b[0m                   \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m this is found to be of type `{integer}`",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;68m│\u001b[0m   \u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m=\u001b[0m\u001b[38;5;68m>\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m!\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54mN\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m{\u001b[0m\u001b[38;5;54m}\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54m,\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54m)\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m│\u001b[0m               \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m│\u001b[0m                                 \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected integer, found `()`",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;68m├\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m▶\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m}\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m│\u001b[0m            ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m `match` arms have incompatible types",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "call to unsafe function `std::intrinsics::transmute` is unsafe and requires unsafe block",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0133] Error:\u001b[0m call to unsafe function `std::intrinsics::transmute` is unsafe and requires unsafe block"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let i = 2;\n",
    "    let v = match i {\n",
    "       0..=3 => i,\n",
    "       _ => println!(\"Nonconforming value:{}\", i)\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "原因很简单: 要赋值给 `v`，就必须保证 `match` 的各个分支返回的值是同一个类型，但是上面一个分支返回数值、另一个分支返回元类型 `()`，自然会出错。\n",
    "\n",
    "既然 `println` 不行，那再试试 `panic`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let i = 2;\n",
    "    let v = match i {\n",
    "       0..=3 => i,\n",
    "       _ => panic!(\"不合规定的值:{}\", i)\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "神奇的事发生了，此处 `panic` 竟然通过了编译。难道这两个宏拥有不同的返回类型？\n",
    "\n",
    "你猜的没错：`panic` 的返回值是 `!`，代表它决不会返回任何值，既然没有任何返回值，那自然不会存在分支类型不匹配的情况。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sized 和不定长类型 DST\n",
    "\n",
    "- https://course.rs/advance/into-types/sized.html\n",
    "\n",
    "TL;DR\n",
    "\n",
    "- **Sized vs. DST**: 大多数类型在编译期就能确定大小并自动实现 `Sized`；`str`、`[T]`、`dyn Trait` 等动态大小类型（DST）只能在运行期确定尺寸。\n",
    "- **DST 使用限制**: 不能直接实例化 DST，必须借助具有固定尺寸的指针包装（如 `&str`、`Box<dyn Trait>`、`&[T]`）。\n",
    "- **泛型默认约束**: 泛型参数隐式要求 `T: Sized`；若需同时接受 `Sized` 与 DST，改为 `T: ?Sized` 并通过引用或智能指针接收。\n",
    "- **特征对象与 `str` 差异**: `Box<dyn Trait>` 可行是因为编译器提供了方法表支持；`Box<str>` 必须通过 `.into()` 等途径让编译器补充长度信息，否则编译失败。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 动态大小类型 DST / unsized 类型\n",
    "\n",
    "- **DST（动态大小类型）**：如 `str`、`[T]`、`dyn Trait`，编译期无法获知具体尺寸，必须到运行期才知道。\n",
    "- **为何常用集合不是 DST**：`Vec`, `String`, `HashMap` 等虽存放堆数据，但栈上持有固定尺寸的指针+元信息，所以整体仍是 `Sized`。\n",
    "- **DST 不能直接实例化**：数组长度若依赖运行时（如 `[123; n]`）或直接声明 `let s: str` 都会编译失败。\n",
    "- **正确用法**：始终经由固定大小的指针包装，例如 `&str`、`&[T]`、`Box<dyn Trait>`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**试图创建动态大小的数组**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "attempt to use a non-constant value in a constant",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0435] Error:\u001b[0m attempt to use a non-constant value in a constant",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_20:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mz\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m this would need to be a `const`",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m error: attempt to use a non-constant value in a constant",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "call to unsafe function `std::intrinsics::transmute` is unsafe and requires unsafe block",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0133] Error:\u001b[0m call to unsafe function `std::intrinsics::transmute` is unsafe and requires unsafe block"
     ]
    }
   ],
   "source": [
    "fn my_function(n: usize) { // n 在编译期无法得知，而数组类型的一个组成部分就是长度，长度变为动态的，自然类型就变成了 unsized \n",
    "    let array = [123; n];\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**切片**\n",
    "\n",
    "切片也是一个典型的 DST 类型，具体详情参见另一篇文章: [易混淆的切片和切片引用](https://course.rs/difficulties/slice.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**str**\n",
    "\n",
    "- 裸类型 `str` 是典型的动态大小类型，无法直接使用；`let s: str = ...` 会编译失败。\n",
    "- `&str` 之所以可用，是因为栈上引用携带指针和长度等元数据，从而拥有固定尺寸。\n",
    "- `String` 同理：自身占用固定大小，堆上字符数据通过指针管理。\n",
    "- 将动态数据“固定化”的关键在于用引用/指针包装，并保存地址与长度信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// error\n",
    "let s1: str = \"Hello there!\";\n",
    "let s2: str = \"How's it going?\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let s3: &str = \"on?\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**特征对象**\n",
    "\n",
    "只能通过引用或 `Box` 的方式来使用特征对象，直接使用将报错！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn foobar_1(thing: &dyn MyThing) {}     // OK\n",
    "fn foobar_2(thing: Box<dyn MyThing>) {} // OK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn foobar_3(thing: MyThing) {}          // ERROR!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**[总结：只能间接使用的 DST](https://course.rs/advance/into-types/sized.html#总结只能间接使用的-dst)**\n",
    "\n",
    "Rust 中常见的 `DST` 类型有: `str`、`[T]`、`dyn Trait`，**它们都无法单独被使用，必须要通过引用或者 `Box` 来间接使用** 。\n",
    "\n",
    "我们之前已经见过，使用 `Box` 将一个没有固定大小的特征变成一个有固定大小的特征对象，那能否故技重施，将 `str` 封装成一个固定大小类型？留个悬念先，我们来看看 `Sized` 特征。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sized 特征\n",
    "\n",
    "- 泛型参数默认带有隐式约束 `T: Sized`，因此只能接受在编译期已知尺寸的类型。\n",
    "- 几乎所有常见类型自动实现 `Sized`，唯有 `str`、trait 等动态大小类型例外，需通过指针/智能指针变成可用的 trait 对象。\n",
    "- 若希望泛型同时支持 `Sized` 与 DST，需要显式写 `T: ?Sized`，并改以引用/指针（如 `&T`）接收参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn generic<T: Sized>(t: T) {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 中的每个 trait 本质上都是动态大小类型，无法单独作为具体值使用。要把某个 trait 作为参数或返回值传递，必须先把它包装成特征对象，例如 `&dyn Trait`、`Box<dyn Trait>` 或 `Rc<dyn Trait>`，这些引用/智能指针提供了固定大小的外壳，使得编译器能正确处理。\n",
    "\n",
    "想在泛型函数中使用动态数据类型怎么办？可以使用 `?Sized` 特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn generic<T: ?Sized>(t: &T) {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`?Sized` 特征用于表明类型 `T` 既有可能是固定大小的类型，也可能是动态大小的类型。还有一点要注意的是，函数参数类型从 `T` 变成了 `&T`，因为 `T` 可能是动态大小的，因此需要用一个固定大小的指针(引用)来包裹它。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Box<str>\n",
    "\n",
    "- `Box<str>` 直接 `Box::new(\"... as str\")` 会失败，因为裸 `str` 没有已知大小，不满足 `Sized`。\n",
    "- `Box<dyn Trait>` 之所以可行，是编译器为特征对象自动维护了调用所需的元信息。\n",
    "- 想要 `Box<str>` 时，交给编译器做类型推断即可：`let s: Box<str> = \"hello\".into();`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在结束前，再来看看之前遗留的问题：使用 `Box` 可以将一个动态大小的特征变成一个具有固定大小的特征对象，能否故技重施，将 `str` 封装成一个固定大小类型？\n",
    "\n",
    "先回想下，章节前面的内容介绍过该如何把一个动态大小类型转换成固定大小的类型： **使用引用指向这些动态数据，然后在引用中存储相关的内存位置、长度等信息**。\n",
    "\n",
    "好的，根据这个，我们来一起推测。首先，`Box<str>` 使用了一个引用来指向 `str`，嗯，满足了第一个条件。但是第二个条件呢？`Box` 中有该 `str` 的长度信息吗？显然是 `No`。那为什么特征就可以变成特征对象？其实这个还蛮复杂的，简单来说，对于特征对象，编译器无需知道它具体是什么类型，只要知道它能调用哪几个方法即可，因此编译器帮我们实现了剩下的一切。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the size for values of type `str` cannot be known at compilation time",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the size for values of type `str` cannot be known at compilation time",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mB\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54mH\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m!\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by a bound introduced by this call",
      " \u001b[38;5;240m  │\u001b[0m                                       \u001b[38;5;54m│\u001b[0m            ",
      " \u001b[38;5;240m  │\u001b[0m                                       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m doesn't have a size known at compile-time",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "cast to unsized type: `&'static str` as `str`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0620] Error:\u001b[0m cast to unsized type: `&'static str` as `str`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54mH\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m!\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                             \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m error: cast to unsized type: `&'static str` as `str`",
      " \u001b[38;5;240m  │\u001b[0m                                               \u001b[38;5;100m│\u001b[0m    ",
      " \u001b[38;5;240m  │\u001b[0m                                               \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider casting to a reference instead: `&`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let s1: Box<str> = Box::new(\"Hello there!\" as str);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "提示得很清晰，不知道 `str` 的大小，因此无法使用这种语法进行 `Box` 进装，但是你可以这么做:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let s1: Box<str> = \"Hello there!\".into();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主动转换成 `str` 的方式不可行，但是可以让编译器来帮我们完成，只要告诉它我们需要的类型即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 枚举和整数\n",
    "\n",
    "- https://course.rs/advance/into-types/enum-int.html\n",
    "\n",
    "在 Rust 中，从枚举到整数的转换很容易，但是反过来，就没那么容易，甚至部分实现还挺邪恶, 例如使用`transmute`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一个真实场景的需求\n",
    "\n",
    "在实际场景中，从整数到枚举的转换有时还是非常需要的，例如你有一个枚举类型，然后需要从外面传入一个整数，用于控制后续的流程走向，此时就需要用整数去匹配相应的枚举(你也可以用整数匹配整数-, -，看看会不会被喷)。\n",
    "\n",
    "既然有了需求，剩下的就是看看该如何实现，这篇文章的水远比你想象的要深，且看八仙过海各显神通。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## C 语言的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Beware of Rust!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#include <stdio.h>\n",
    "\n",
    "enum atomic_number {\n",
    "    HYDROGEN = 1,\n",
    "    HELIUM = 2,\n",
    "    // ...\n",
    "    IRON = 26,\n",
    "};\n",
    "\n",
    "{\n",
    "    enum atomic_number element = (atomic_number)26;\n",
    "\n",
    "    if (element == IRON) {\n",
    "        printf(\"Beware of Rust!\\n\");\n",
    "    }\n",
    "\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 但是在 Rust 中，以下代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "enum MyEnum {\n",
    "    A = 1,\n",
    "    B,\n",
    "    C,\n",
    "}\n",
    "\n",
    "{\n",
    "    // 将枚举转换成整数，顺利通过\n",
    "    let x = MyEnum::C as i32;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_5:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m this expression has type `i32`",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mM\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;54mE\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54mA\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `i32`, found `MyEnum`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_5:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m this expression has type `i32`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mM\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;54mE\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54mB\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `i32`, found `MyEnum`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_5:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m this expression has type `i32`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mM\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;54mE\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54mC\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `i32`, found `MyEnum`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let x = MyEnum::C as i32;\n",
    "\n",
    "// 将整数转换为枚举，失败\n",
    "match x {\n",
    "    MyEnum::A => {}\n",
    "    MyEnum::B => {}\n",
    "    MyEnum::C => {}\n",
    "    _ => {}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用三方库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[dependencies]\n",
    "num-traits = \"0.2.14\"\n",
    "num-derive = \"0.3.3\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TryFrom + 宏"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::convert::TryFrom;\n",
    "\n",
    "// 代码定义了从i32到MyEnum的转换\n",
    "impl TryFrom<i32> for MyEnum {\n",
    "    type Error = ();\n",
    "\n",
    "    fn try_from(v: i32) -> Result<Self, Self::Error> {\n",
    "        match v {\n",
    "            x if x == MyEnum::A as i32 => Ok(MyEnum::A),\n",
    "            x if x == MyEnum::B as i32 => Ok(MyEnum::B),\n",
    "            x if x == MyEnum::C as i32 => Ok(MyEnum::C),\n",
    "            _ => Err(()),\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "c\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::convert::TryInto;\n",
    "\n",
    "{\n",
    "    let x = MyEnum::C as i32;\n",
    "\n",
    "    match x.try_into() { // 使用TryInto来实现转\n",
    "        Ok(MyEnum::A) => println!(\"a\"),\n",
    "        Ok(MyEnum::B) => println!(\"b\"),\n",
    "        Ok(MyEnum::C) => println!(\"c\"),\n",
    "        Err(_) => eprintln!(\"unknown number\"),\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 使用宏来简化，自动根据枚举的定义来实现TryFrom特征\n",
    "\n",
    "#[macro_export]\n",
    "macro_rules! back_to_enum {\n",
    "    ($(#[$meta:meta])* $vis:vis enum $name:ident {\n",
    "        $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*\n",
    "    }) => {\n",
    "        $(#[$meta])*\n",
    "        $vis enum $name {\n",
    "            $($(#[$vmeta])* $vname $(= $val)?,)*\n",
    "        }\n",
    "\n",
    "        impl std::convert::TryFrom<i32> for $name {\n",
    "            type Error = ();\n",
    "\n",
    "            fn try_from(v: i32) -> Result<Self, Self::Error> {\n",
    "                match v {\n",
    "                    $(x if x == $name::$vname as i32 => Ok($name::$vname),)*\n",
    "                    _ => Err(()),\n",
    "                }\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Got C\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "back_to_enum! {\n",
    "    enum MyEnum {\n",
    "        A = 1,\n",
    "        B,\n",
    "        C,\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let raw = 3_i32;\n",
    "\n",
    "    match raw.try_into() {\n",
    "        Ok(MyEnum::A) => println!(\"Got A\"),\n",
    "        Ok(MyEnum::B) => println!(\"Got B\"),\n",
    "        Ok(MyEnum::C) => println!(\"Got C\"),\n",
    "        Err(_) => eprintln!(\"Unknown variant\"),\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 邪恶之王 `std::mem::transmute`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found C\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#[repr(i32)] // 最好使用#[repr(..)]来控制底层类型的大小，免得本来需要 i32，结果传入 i64，最终内存无法对齐，产生奇怪的结果\n",
    "enum MyEnum {\n",
    "    A = 1, B, C\n",
    "}\n",
    "\n",
    "{\n",
    "    let x = MyEnum::C;\n",
    "    let y = x as i32;\n",
    "    let z: MyEnum = unsafe { std::mem::transmute(y) };\n",
    "\n",
    "    // match the enum that came from an int\n",
    "    match z {\n",
    "        MyEnum::A => { println!(\"Found A\"); }\n",
    "        MyEnum::B => { println!(\"Found B\"); }\n",
    "        MyEnum::C => { println!(\"Found C\"); }\n",
    "    }\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
